﻿#define _CRT_SECURE_NO_WARNINGS
#define HAVE_REMOTE
#define WIN32

#include <pcap.h>
#include <Packet32.h>
#include <ntddndis.h>
#include <string.h>
#include <time.h>

#pragma comment(lib, "Packet")
#pragma comment(lib, "wpcap")
#pragma comment(lib, "WS2_32")

// IP 头部结构体
typedef struct ip_header {
    u_char ver_ihl;
    u_char tos;
    u_short tlen;
    u_short identification;
    u_short flags_fo;
    u_char ttl;
    u_char proto;
    u_short crc;
    u_char saddr[4];
    u_char daddr[4];
    u_int op_pad;
} ip_header;

// 以太网头部结构体
typedef struct mac_header {
    u_char dest_addr[6];
    u_char src_addr[6];
    u_char type[2];
} mac_header;

// 数据包处理函数
void packet_handler(u_char* param, const struct pcap_pkthdr* header, const u_char* pkt_data);

int main() {
    int inum;
    pcap_if_t* alldevs;
    pcap_if_t* d;
    char errbuf[PCAP_ERRBUF_SIZE];
    pcap_t* adhandle;
    int i = 0;
    u_int netmask;
    char packet_filter[] = "ip";
    struct bpf_program fcode;

    // 获取设备列表
    if (pcap_findalldevs_ex((char*)PCAP_SRC_IF_STRING, NULL, &alldevs, errbuf) == -1) {
        fprintf(stderr, "Error in pcap_findalldevs: %s\n", errbuf);
        exit(1);
    }

    // 打印设备列表
    for (d = alldevs; d; d = d->next) {
        printf("%d. %s", ++i, d->name);
        if (d->description)
            printf(" (%s)\n", d->description);
        else
            printf(" (No description available)\n");
    }

    // 选择设备
    if (i == 0) {
        printf("\nNo interfaces found! Make sure WinPcap is installed.\n");
        return -1;
    }
    printf("Enter the interface number (1-%d):", i);
    scanf("%d", &inum);
    if (inum < 1 || inum > i) {
        printf("\nInterface number out of range.\n");
        pcap_freealldevs(alldevs);
        return -1;
    }

    // 定位用户选择的设备
    for (d = alldevs, i = 0; i < inum - 1; d = d->next, i++);

    // 打开设备
    if ((adhandle = pcap_open(d->name, 65536, PCAP_OPENFLAG_PROMISCUOUS, 1000, NULL, errbuf)) == NULL) {
        fprintf(stderr, "\nUnable to open the adapter. %s is not supported by WinPcap\n", d->name);
        pcap_freealldevs(alldevs);
        return -1;
    }

    // 检查数据链路层
    if (pcap_datalink(adhandle) != DLT_EN10MB) {
        fprintf(stderr, "\nThis program works only on Ethernet networks.\n");
        pcap_freealldevs(alldevs);
        return -1;
    }

    if (d->addresses != NULL)
        netmask = ((struct sockaddr_in*)(d->addresses->netmask))->sin_addr.S_un.S_addr;
    else
        netmask = 0xffffff;

    // 编译过滤规则
    if (pcap_compile(adhandle, &fcode, packet_filter, 1, netmask) < 0) {
        fprintf(stderr, "\nUnable to compile the packet filter. Check the syntax.\n");
        pcap_freealldevs(alldevs);
        return -1;
    }

    // 设置过滤规则
    if (pcap_setfilter(adhandle, &fcode) < 0) {
        fprintf(stderr, "\nError setting the filter.\n");
        pcap_freealldevs(alldevs);
        return -1;
    }

    printf("\nlistening on %s...\n", d->description);
    pcap_freealldevs(alldevs);

    // 开始捕获数据包
    pcap_loop(adhandle, 0, packet_handler, NULL);

    return 0;
}

// 数据包处理函数
void packet_handler(u_char* param, const struct pcap_pkthdr* header, const u_char* pkt_data) {
    struct tm* ltime;
    mac_header* mh;
    ip_header* ih;
    time_t local_tv_sec;
    char timestr[16];
    FILE* fp;

    local_tv_sec = header->ts.tv_sec;
    ltime = localtime(&local_tv_sec);
    strftime(timestr, sizeof(timestr), "%H:%M:%S", ltime);

    mh = (mac_header*)pkt_data;
    ih = (ip_header*)(pkt_data + sizeof(mac_header));

    // 打开 CSV 文件以追加模式写入
    fp = fopen("data.csv", "a+");
    if (fp == NULL) {
        fprintf(stderr, "Failed to open file.\n");
        return;
    }

    // 写入时间
    fprintf(fp, "%s,", timestr);

    // 写入源 MAC 地址
    for (int i = 0; i < 6; i++) {
        if (i != 5)
            fprintf(fp, "%02x:", mh->src_addr[i]);
        else
            fprintf(fp, "%02x,", mh->src_addr[i]);
    }

    // 写入源 IP 地址
    for (int i = 0; i < 4; i++) {
        if (i != 3)
            fprintf(fp, "%d.", ih->saddr[i]);
        else
            fprintf(fp, "%d,", ih->saddr[i]);
    }

    // 写入目标 MAC 地址
    for (int i = 0; i < 6; i++) {
        if (i != 5)
            fprintf(fp, "%02x:", mh->dest_addr[i]);
        else
            fprintf(fp, "%02x,", mh->dest_addr[i]);
    }

    // 写入目标 IP 地址
    for (int i = 0; i < 4; i++) {
        if (i != 3)
            fprintf(fp, "%d.", ih->daddr[i]);
        else
            fprintf(fp, "%d,", ih->daddr[i]);
    }

    // 写入帧长度
    fprintf(fp, "%d\n", header->len);

    fclose(fp);
}